﻿// <copyright file="ReadOnlyDictionary.cs" company="Anatoly Sereda">
// © 2009 Anatoly Sereda
//
// This source is subject to the Microsoft Public License.
// Please see the License.txt file for more information.
// All other rights reserved.
//
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// </copyright>
// <author>Anatoly Sereda</author>
// <email>neonnvr@live.com</email>
// <date>2009-08-04</date>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace MafMefInterop.Internal
{
	internal class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
	{
		public static readonly ReadOnlyDictionary<TKey, TValue> Empty = new ReadOnlyDictionary<TKey, TValue>();

		private IDictionary<TKey, TValue> dictionary;
		private bool empty;

		public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
		{
			if (dictionary == null)
			{
				throw new ArgumentNullException("dictionary");
			}

			this.dictionary = dictionary;
		}

		private ReadOnlyDictionary()
		{
			this.empty = true;
		}

		public IEnumerable<TKey> Keys
		{
			get
			{
				if (this.empty)
				{
					yield break;
				}

				foreach (TKey key in this.dictionary.Keys)
				{
					yield return key;
				}
			}
		}

		public IEnumerable<TValue> Values
		{
			get
			{
				if (this.empty)
				{
					yield break;
				}

				foreach (TValue value in this.dictionary.Values)
				{
					yield return value;
				}
			}
		}

		public int Count
		{
			get
			{
				if (this.empty)
				{
					return 0;
				}

				return this.dictionary.Count;
			}
		}

		ICollection<TKey> IDictionary<TKey, TValue>.Keys
		{
			get { return new ReadOnlyCollection<TKey>(this.Keys.ToList()); }
		}

		ICollection<TValue> IDictionary<TKey, TValue>.Values
		{
			get { return new ReadOnlyCollection<TValue>(this.Values.ToList()); }
		}

		bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
		{
			get { return true; }
		}

		TValue IDictionary<TKey, TValue>.this[TKey key]
		{
			get
			{
				return this[key];
			}

			set
			{
				throw new NotSupportedException();
			}
		}

		public TValue this[TKey key]
		{
			get
			{
				if (this.empty)
				{
					throw new KeyNotFoundException();
				}

				return this.dictionary[key];
			}
		}

		public bool TryGetValue(TKey key, out TValue value)
		{
			if (this.empty)
			{
				value = default(TValue);
				return false;
			}

			return this.dictionary.TryGetValue(key, out value);
		}

		public bool ContainsKey(TKey key)
		{
			if (this.empty)
			{
				return false;
			}

			return this.dictionary.ContainsKey(key);
		}

		public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
		{
			if (this.empty)
			{
				return this.GetEmptyEnumerator();
			}
			else
			{
				return this.dictionary.GetEnumerator();
			}
		}

		bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
		{
			return this.dictionary.Contains(item);
		}

		void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			this.dictionary.CopyTo(array, arrayIndex);
		}

		IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.GetEnumerator();
		}

		bool IDictionary<TKey, TValue>.Remove(TKey key)
		{
			throw new NotSupportedException();
		}

		void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
		{
			throw new NotSupportedException();
		}

		void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
		{
			throw new NotSupportedException();
		}

		void ICollection<KeyValuePair<TKey, TValue>>.Clear()
		{
			throw new NotSupportedException();
		}

		bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
		{
			throw new NotSupportedException();
		}

		private IEnumerator<KeyValuePair<TKey, TValue>> GetEmptyEnumerator()
		{
			yield break;
		}
	}
}
